package smallChanges.Tokenization;

import net.sourceforge.pmd.ast.SimpleJavaNode;
import smallChanges.statements.MultiTokenCodeRange2D;
import smallChanges.util.HashCodeUtil;

/**
 * Code within a program encompassing a given range,
 * from a beginning line number/column number to
 * an ending line number/column (hence the 2D if you consider the
 * line to be one coordinate and the column to be the other).  
 * This class provides
 * the basis for both a single token {@link SCToken} as well
 * as statements and expressions {@link MultiTokenCodeRange2D}.
 * 
 * 
 * @author jspacco
 *
 */
public class CodeRange2D implements Comparable<CodeRange2D>, ICodeRange2D
{
	protected int beginColumn;
	protected int beginLine;
	protected int endColumn;
	protected int endLine;

	public CodeRange2D() {
		super();
	}
	
	public CodeRange2D(int beginLine, int beginColumn, int endLine, int endColumn)
    {
    	this.beginColumn=beginColumn;
        this.endColumn=endColumn;
        this.beginLine=beginLine;
        this.endLine=endLine;
    }
	
	public int hashCode() {
		int result=HashCodeUtil.SEED;
        result = HashCodeUtil.hash(result, this.beginLine);
        result = HashCodeUtil.hash(result, this.endLine);
        result = HashCodeUtil.hash(result, this.beginColumn);
        result = HashCodeUtil.hash(result, this.endColumn);
        return result;
	}
	
	public String toString() {
		return getCoords();
	}
	
	public boolean equals(Object o)
	{
		if (!(o instanceof CodeRange2D))
            return false;
        if (o==null)
            return false;
        CodeRange2D other=(CodeRange2D)o;
		return this.beginLine==other.beginLine &&
        this.endLine==other.endLine &&
        this.beginColumn==other.beginColumn &&
        this.endColumn==other.endColumn;
	}

	public int compareTo(CodeRange2D other)
	{
	    // XXX NOTE: fields can have weirdly overlapping coordiante ranges
	    // For example, consider this field declaration statement:
	    // int x, y;
	    // In this example, "int x" is one field and "int y" is the other,
	    // but the "int y" has tokens "x, " inside its range, though those
	    // tokens will not be in included in its token set.
	    // XXX be sure that when saving field statements, you save the
	    // precise tokens, and NOT just the whole range.
	    int beginLineDiff=this.beginLine - other.beginLine;
	    if (beginLineDiff!=0) {
	        return beginLineDiff;
	    }
	    int beginColumnDiff=this.beginColumn - other.beginColumn;
	    if (beginColumnDiff!=0) {
	        return beginColumnDiff;
	    }
	    int endLineDiff=this.endLine - other.endLine;
	    if (endLineDiff!=0) {
	        return endLineDiff;
	    }
	    return this.endColumn - other.endColumn;
	}
	
	public String getCoords()
	{
		return "(" +getBeginLine()+", "+getBeginColumn()+
		") ("+
		getEndLine()+", "+getEndColumn()+")";
	}

	public int getBeginColumn()
	{
	    return beginColumn;
	}

	public void setBeginColumn(int beginColumn)
	{
	    this.beginColumn = beginColumn;
	}

	public int getBeginLine()
	{
	    return beginLine;
	}

	public void setBeginLine(int beginLine)
	{
	    this.beginLine = beginLine;
	}

	public int getEndColumn()
	{
	    return endColumn;
	}

	public void setEndColumn(int endColumn)
	{
	    this.endColumn = endColumn;
	}

	public int getEndLine()
	{
	    return endLine;
	}

	public void setEndLine(int endLine)
	{
	    this.endLine = endLine;
	}

	public void setCoordinatesFromNode(SimpleJavaNode node)
	{
		setBeginLine(node.getBeginLine());
		setBeginColumn(node.getBeginColumn());
		setEndLine(node.getEndLine());
		setEndColumn(node.getEndColumn());
	}
	
//	public boolean contains(CodeRange2D other)
//	{
//		boolean retVal = false;
//		if(other!=null)
//		{
//			if( beginLine < other.getBeginLine() && endLine > other.getEndLine())
//			{
//				retVal = true;
//			}
//			else if( beginLine > other.getBeginLine() || endLine < other.getEndLine())
//			{
//				retVal = false;
//			}
//			else if( (beginLine < other.getBeginLine() || 
//						(beginLine == other.getBeginLine() && beginColumn < other.getBeginColumn() )
//						&& (endLine > other.getEndLine() || 
//								(endLine == other.getEndLine() && endColumn > other.getEndColumn() ))))
//			{
//				retVal = true;
//			}
//		}
//		return retVal;
//	}
}